﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<algorithm>
using namespace std;
using std::cout;
using std::endl;

void test_string8()
{
	string s1("hello world");
	cout << s1 << endl;

	//等价于赋值（清空再赋值）
	s1.assign("111111");
}

//insert
//插入
void test_string9()
{
	string s1("hello world");
	cout << s1 << endl;

	//0:插入的起点位）
	//插入字符串：" "
	s1.insert(0,"xxx");
	cout << s1 << endl;
	//时间复杂度o(n):如果待插入的字符串中只有一个字符：原数据过长，则每个字符都需要后移，消耗不成正比

	//不支持只插入一个字符: ''：只有迭代器版本：27的insert不支持（带上长度1可以支持
	s1.insert(0, 1, 'y');
	//s1.insert(0, 'y');//❌
	cout << s1 << endl;

	//迭代器版本插入一个字符
	s1.insert(s1.begin(), 'y');
	cout << s1 << endl;

	string s2("hello!!!!");

	//迭代器：插入一个区间
	s2.insert(s2.begin()+3, s1.begin(), s1.end());
	//s1从开始到结尾，插入到s2开始+3的位置
	cout << s2 << endl;

	//insert慎用：效率不高
	//且字符的插入：单插，迭代器插入
	//实践中需求也不高
}

//erase:删除（和insert类似慎用）
//参数列表：(size_t pos=0;size_t len=npos);
//从pos位置开始删除len个字符，不传入参数：全删

void test_string10()
{
	string s1("hello world");
	cout << s1 << endl;

	s1.erase(1,2);
	//从pos位置开始删除len个字符
	cout << s1 << endl;

	s1.erase(5);
	//pos后面全部删除
	cout << s1 << endl;

	s1.erase(1, 1000);//len可以超出原有的长度：不会越界：有多少删多少

	//也可以用迭代器

	//replace
	//替换
	string s2("hello !!!!!");
	s2.replace(5,1,"%20");
	//从pos开始的1个字符替换为” “
	cout << s2 << endl;


	//题目：将所有空格都替换为。。。。。
	string s3("hello !! !! !");
	for (size_t i = 0; i < s3.size(); i++)
	{
		if (s3[i] == ' ')
		{
			s3.replace(i, 1, "%20");
			//替换之后往后走%20：3个字符长度
			i += 3;
		}
		
	}
	//！！！！！
	//如果替换位和待替换的位置是相等的：那么替换之后原来的字符串不会有多余的改动，如果不相等，那么其余字符串，都会改变原来的位置：效率不高
	//解决方案1：先计算挪动的位置
	//解决方案2：不是空格的字符：在其原来的位置上+=（直接一步挪动到替换后的位置，提高效率）
	//          如果是空格：在后面添加需要替换的字符串" "

	//********for (auto c : s)************
		//中s为一个容器，效果是利用c遍历并获得s容器中的每一个值，
		// 但是c无法影响到s容器中的元素

	string s4 = ("hello world hello bit");
	string s5;
	for (auto ch : s4)
	{
		if (ch != ' ')
		{
			s5 += ch;
		}
		else
		{
			s5 += "%20";
		}
	}


	cout << s3 << endl;

}

void test_string11()
{
	//string s1 = ("hello world hello bit");
	//cout << s1.size() << endl;
	//cout << s1.capacity() << endl;
	//cout << s1.max_size() << endl;
	//开不了2G这么大的字符
	//TestPushBack();
	string s1("11111111111111");
	string s2("11111111111111111111111111111111111");
//扩容
	cout << s1.capacity() << endl;
	//reserve 保留
	//reverse 反转：逆置

	//用于扩容
	s1.reserve(100);
	cout << s1.capacity() << endl;
	//reserve可能比给的值大

	s1.reserve(14);
	cout << s1.capacity() << endl;
	//还可以缩容（有的编译器不能缩容）：缩小到原来的大小可以缩
	//vs其他大小默认不能缩（linux可以缩到指定大小）
	//可以但不建议（扩容缩容）
}

void TestPushBack()
{
	string s;
	size_t sz = s.capacity();
	//第一次扩容：
	cout << "capacity changed:" << sz << endl;

	cout << "making s grow:\n";
	//每当容量有变化时（扩容后）：就打印
	for (int i = 0; i < 200; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed:" << sz << endl;
		}
	}
}
//：vs下：第一次是二倍扩容：后续都是1.5倍
//空间存放： buf（第一次） ->  堆
//capacity的空间：比实际空间少一个：是预留给"/0"的

void  test_string12()
{
	//resize
	string s1;
	//76543:只是开好了空间：还不能用下标进行访问
	//s1.resize(5, '0');
	s1.resize(5);//不传初始化参数：默认参数'\0'(ascll码为0的字符)
	s1[4] = '3';
	s1[3] = '4';
	s1[2] = '5';
	s1[1] = '6';
	s1[0] = '7';

	//插入
	string s2("hello world");
	s2.resize(20, 'x');//多开扩容：影响capacity
	//'x'会在已有的数据后面补，不会影响原来的字符数据

	//删除
	s2.resize(5);
	//vs  size会缩，capacity不会缩
	//缩容与否取决于编译器

	try {
		//s2[10];
		//越界
		//访问pos位置字符
		// []是暴力检查
		// 直接打回
		// at是抛异常
		// 
		//s2.at(10);
		//被提醒，不被打回
	}
	catch (const exception& e) 
	{
		cout<< e.what() << '\n';
	}

	//读文件：
	//.c_str:更好的兼容C语言的接口
	string file("test.cpp");
	FILE* font = fopen(file.c_str(), "r");
	//"r"	打开一个文本文件，可以 读取文件read。
	char ch = fgetc(font);
	while (ch!=EOF)
	{
		cout << ch;
		ch = fgetc(font);
	}
}

void test_string13()
{
	//find:查找
	string file("test.cpp.zip");
	//查找文件的后缀：不能直接找.xxx，有可能有多个.xxx
	//rfind   倒着查找
	
	//找到点：
	size_t pos = file.rfind('.');
	//取完：
	//substr:从pos位置开始生成一个新的字符串（长度参数）返回
	//string suffix = file.substr(pos, file.size() - pos);
	//也可以不传第二个参数：找到结尾（默认的参数：enpos）
	string suffix = file.substr(pos);
	
	cout << suffix << endl;

	//域名：(//后方)blog.csdn.net
	string url("https://blog.csdn.net/qq_40492048/article/details/85346079");
	//要分部分取出：协议，域名，资源符
	//find找出对应第一个出现的标识符的地址，不断地取字串...
	//第一段
	size_t pos1 = url.find(':');
	string url1 = url.substr(0,pos1 - 0);
	cout << url1 << endl;
	//第二段：从pos1+3的位置开始查找（跳过：//）
	size_t pos2 = url.find('/',pos1 + 3);
	string url2 = url.substr(pos1 + 3, pos2-(pos1+3));
	cout << url2 << endl;
	//第三段：
	size_t pos3 = url.find('\0', pos2 + 1);
	string url3 = url.substr(pos2 + 1);
	cout << url3 << endl;

}

void test_string14()
{
	string s1 = "hello";
	string s2 = "world";

	string ret1 = s1 + s2;
	cout << ret1 << endl;

	string ret2 = s1 + "xxxxx";
	cout << ret2 << endl;

	string ret3 = "xxxxx" + s1;
	cout << ret3 << endl;//这个不能写成成员函数

	//helloworld
	//helloxxxxx
	//xxxxxhello
	//const char*和字符是可以相加的

	//比较大小：ascll(字典序比较)(与长度无关：按位一次比较，大则全大)
	cout << (s1 < s2) << endl;//1:成立

	//operator+（在字符串与const char*的运算中比较冗余：char可以隐式类型转换成string）
}


//int main()
//{
//	//test_string8();
//	//test_string9();
//	//test_string10();
//	//test_string11();
//	
//	//test_string12();
//	//test_string13();
//	test_string14();
//	//test_string13();
//	//test_string13();
//	//test_string13();
//
//	return 0;
//}


































































































